package vy.org.app.page.printlabel.report.instance;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.vy.dal.dao.ViewVyPrintLabelDAO;
import org.vy.dal.dao.ViewVyPrintLabelDO;
import org.vy.dal.dao.VyPrintLabelReportInstanceDAO;
import org.vy.dal.dao.VySubscriptionTransactionDAO;
import org.vy.dal.dao.VySubscriptionTransactionDO;
import org.vy.dal.dao.lookup.ViewVyLookupCitiesDAO;
import org.vy.dal.dao.lookup.ViewVyLookupCitiesDO;

import vy.org.app.common.Config;
import vy.org.app.common.Logger;
import vy.org.app.common.Logger.LogLevel;

public class PrintLabelReport extends ReportInstance {

	public static final String DELIMITER = " AND ";
	public static final String EXTN = ".html";
	private static Map<String, Map<String, ViewVyLookupCitiesDO>> cities = new HashMap<String, Map<String, ViewVyLookupCitiesDO>>(); 
	private static Map<String, Map<String, ViewVyLookupCitiesDO>> states = new HashMap<String, Map<String, ViewVyLookupCitiesDO>>(); 
	private static Map<String, ViewVyLookupCitiesDO> countries = new HashMap<String, ViewVyLookupCitiesDO>(); 
	public static SimpleDateFormat _DTFMT = new SimpleDateFormat("MMM yyyy");

	protected PrintLabelReport(Integer reportId) throws Exception {
		super(reportId);
	}

	@Override
	public void run() {
		//parse criteria
		//form query
		//execute query
		//iterate over data and start writing to file
		//after every 100 record check for status not cancelled
		//at end close file
		//read file in bytes and upload to db
		//set the status as completed
		//delete the file
		//remove the instance from manager
		
		String[] criterias = report.getCriteria().split(DELIMITER);
		String sqlClause = " 1=1 ";
		String country = null;
		for(String term : criterias){
			String[] val = term.split("=");
			if("PATRIKA_ID".equals(val[0]))
				sqlClause += DELIMITER + "PATRIKA_ID LIKE " + val[1];
			if("ceil(datediff(end_date, start_date)/30)".equals(val[0])
					|| "PERIOD_MONTH".equals(val[0]))
				sqlClause += DELIMITER + "PERIOD_MONTH LIKE " + val[1];
			if("COUNTRY".equals(val[0])){
				sqlClause += DELIMITER + "COUNTRY LIKE " + val[1] +" ";
				country = val[1].replaceAll("'", "");
			}
			if("STATE".equals(val[0]))
				sqlClause += DELIMITER + "STATE_OR_REGION LIKE " + val[1] +" ";
			if("CITY".equals(val[0]))
				sqlClause += DELIMITER + "CITY LIKE " + val[1] +" ";
			if("QUANTITY".equals(val[0]) && "N".equals(val[1])){
				sqlClause += DELIMITER + "QUANTITY > 1 ";
			}else if("QUANTITY".equals(val[0]) && "1".equals(val[1])){
				sqlClause += DELIMITER + "QUANTITY = 1 ";
			}
//			if("WEEK_OFFSET_INDEX".equals(val[0]))
//				sqlClause += DELIMITER + "WEEK_OFFSET_INDEX LIKE '" + val[1] +"' ";
		}
		sqlClause += DELIMITER + " IS_ACTIVE = true AND (EXTRACT(YEAR_MONTH FROM CURRENT_DATE) between EXTRACT(YEAR_MONTH FROM START_DATE) and EXTRACT(YEAR_MONTH FROM END_DATE))";
//		sqlClause += DELIMITER + " LAST_UPDATED_ON > '2011-05-11' ";
		Logger.log(LogLevel.DEBUG, sqlClause);
		try{
			//countries 
			List<ViewVyLookupCitiesDO> lstCountry = null;
			
			if(!"%".equals(country)){
				ViewVyLookupCitiesDO ctry = ViewVyLookupCitiesDAO.findByCountryCode(country);
				lstCountry = new ArrayList<ViewVyLookupCitiesDO>();
				lstCountry.add(ctry);
			}else{				
				lstCountry = ViewVyLookupCitiesDAO.findUniqueCountries();
			}
			for(ViewVyLookupCitiesDO dto : lstCountry){
				countries.put(dto.getCountryCode(), dto);
				List<ViewVyLookupCitiesDO> lstStates = ViewVyLookupCitiesDAO.findStateByCountry(dto.getCountryCode());
				Map<String, ViewVyLookupCitiesDO> locState = new HashMap<String, ViewVyLookupCitiesDO>();
				for(ViewVyLookupCitiesDO sto : lstStates){
					locState.put(sto.getStateCode(), sto);
					List<ViewVyLookupCitiesDO> lstCities = ViewVyLookupCitiesDAO.findCitiesByStateAndCountry(sto.getStateCode(), dto.getCountryCode());
					Map<String, ViewVyLookupCitiesDO> locCity = new HashMap<String, ViewVyLookupCitiesDO>();
					for(ViewVyLookupCitiesDO cto : lstCities){
						locCity.put(cto.getCityCode(), cto);
					}
					cities.put(dto.getCountryCode()+"->"+sto.getStateCode(), locCity);
				}
				states.put(dto.getCountryCode(), locState);
			}
			
			List<ViewVyPrintLabelDO> results = ViewVyPrintLabelDAO.findByParam(sqlClause);
			processResults(results);
			if(instance.getStatus() != ReportStatusEnum.CANCELLED.getId())
				uploadResult();
			
			instance.setEndTime(new Date());
			VyPrintLabelReportInstanceDAO.updateStatusEndTime(instance);

			remove();
		}catch(Exception e){
			e.printStackTrace();
			Logger.log(LogLevel.DEBUG, e);
			//set status failed
			try{
				instance.setStatus(ReportStatusEnum.FAILED.getId());
				instance.setEndTime(new Date());
				VyPrintLabelReportInstanceDAO.updateStatusEndTime(instance);
			}catch(Exception es){
				Logger.log(LogLevel.DEBUG, es);
				es.printStackTrace();
			}
		}
		remove();
	}
	
	public void processResults(List<ViewVyPrintLabelDO> results) throws IOException, FileNotFoundException {
		String fileName = Config.getProperty("FILE_PATH") + instance.getReportInstanceId() + EXTN;
		File file = new File(fileName);
		if(file.exists())
			file.delete();
		file.createNewFile();
		
		FileWriter fw = new FileWriter(fileName,true);
		fw.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">")
			.append("\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">")
			.append("\n<title>")
			.append(report.getReportName())
			.append("</title><style>.break{page-break-before: always;} .kd010 { font-family:\"Kruti Dev 010\"; font-size:20px; }.rt{text-align:right;}.lt{text-align:left;}.info{font-size:10px;color:#999;}.rst{font-size:14px;font-family:verdana, Sans-serif,Arial;color:#222;width:850px}.rst td {padding:20px 30px;}.rst table td {padding:2px 2px;}.name{font-size:14px;font-weight:bold;}</style></head><body>");
		fw.append("\n<h1>"+report.getReportName()+" "+ _DTFMT.format(new Date())  + "</h1>")
		.append("\n<table class='rst' cellpadding='0' cellspacing='0' border='0'>");
		
		long l = 0;
		Calendar cal = Calendar.getInstance();
		ViewVyPrintLabelDO addr = null;
		int qty = 0;
		String grpId = null;
		for(ViewVyPrintLabelDO dto : results){
			
			//First check for group id
			// Yes - sum up all quantities
			//      get the record with label address
			// No - get the current record label address and current quantity
			// if quantity less <= 50 create single block else multiple block
			// each block check for label address language, if hindi print hindi else english
			
			if(dto.getPrintLabelGroupId() == null || "".equals(dto.getPrintLabelGroupId()))
				continue;
			
			VySubscriptionTransactionDO subDO = new VySubscriptionTransactionDO();
			subDO.setSubscriptionId(dto.getSubscriptionId());
			int Q = (cal.get(Calendar.MONTH)+3)/3;
			String MQY = cal.get(Calendar.MONTH)+""+Q+""+cal.get(Calendar.YEAR);
			subDO.setForMQY(Integer.parseInt(MQY));
			subDO.setVyId(dto.getVyId());
			subDO.setAddressId(dto.getAddressId());
			subDO.setIsDispatched(false);
			subDO.setCreatedDate(new Date());
			subDO.setDispatchMode(dto.getDeliveryMode());
			subDO.setReportInstanceId(instance.getReportInstanceId());
			subDO.setComments(dto.getInstruction()!=null?dto.getInstruction() : "");
			try{
				subDO = VySubscriptionTransactionDAO.insert(subDO);
				dto.setIsActive(true);
			}catch(Exception e){
				e.printStackTrace();
				dto.setIsActive(false);
			}
			
			qty += dto.getQuantity();
			grpId = dto.getPrintLabelGroupId();
			if(dto.getIsLabelAddress() == null || dto.getIsLabelAddress() == false)
				addr = null;
			else
				addr = dto;

			if(addr != null && grpId != null)
				l=print(addr, qty, fw, l);
			
			if(l%100 == 0 && ReportStatusEnum.CANCELLED.getId() == instance.getStatus())
			{
				fw.flush();
				fw.close();
				return;
			}
		}
		Logger.log(LogLevel.DEBUG, "TOTAL ROWS = "+ l);

		for(ViewVyPrintLabelDO dto : results){
			
			//First check for group id
			// Yes - sum up all quantities
			//      get the record with label address
			// No - get the current record label address and current quantity
			// if quantity less <= 50 create single block else multiple block
			// each block check for label address language, if hindi print hindi else english
			
			if(dto.getPrintLabelGroupId() != null || !dto.getIsActive())
				continue;
			
			VySubscriptionTransactionDO subDO = new VySubscriptionTransactionDO();
			subDO.setSubscriptionId(dto.getSubscriptionId());
			int Q = (cal.get(Calendar.MONTH)+3)/3;
			String MQY = cal.get(Calendar.MONTH)+""+Q+""+cal.get(Calendar.YEAR);
			subDO.setForMQY(Integer.parseInt(MQY));
			subDO.setVyId(dto.getVyId());
			subDO.setAddressId(dto.getAddressId());
			subDO.setIsDispatched(false);
			subDO.setCreatedDate(new Date());
			subDO.setDispatchMode(dto.getDeliveryMode());
			subDO.setReportInstanceId(instance.getReportInstanceId());
			subDO.setComments(dto.getInstruction()!=null?dto.getInstruction() : "");
			try{
				subDO = VySubscriptionTransactionDAO.insert(subDO);
				dto.setIsActive(true);
			}catch(Exception e){
				//dto.setIsActive(false);
				e.printStackTrace();
				continue;
			}

			qty=dto.getQuantity();
			l=print(dto, qty, fw, l);
			if(l%100 == 0 && ReportStatusEnum.CANCELLED.getId() == instance.getStatus())
			{
				fw.flush();
				fw.close();
				return;
			}
			
		}
		fw.append("\n</tr></table></body></html>");
		instance.setStatus(ReportStatusEnum.SUCCESS.getId());
		Logger.log(LogLevel.DEBUG, "TOTAL ROWS = "+ l);
		fw.flush();
		fw.close();
	}

	private long print(ViewVyPrintLabelDO addr, int qty, FileWriter fw, long l) throws IOException {

		String clz = "";
		if(l>0 && l%12==0){
			clz = "break";
		}
		
		if(l%2==0 && l > 0){
			fw.append("\n</tr>");
		}
		if(l==0 || l%2==0) 
			fw.append("\n<tr class=\""+ clz +"\">");
		
		int q = (qty <= 50)? qty : 50;
		String id = (addr.getPrintLabelGroupId()==null)? addr.getSubscriptionId() : addr.getPrintLabelGroupId();
		
		fw.append("\n<td valign='top'><table width='100%' cellpadding='0' cellspacing='0' border='0'>");
		
		fw.append("\n<tr><td class='lt info'>ID : "+ id +"</td><td class='rt info'>Qty : "+ q +"</td></tr>");
		if("hi".equals(addr.getPrintLanguage())){
			if(addr.getRegionalLangName() != null && !"".equals(addr.getRegionalLangName().trim()))
				fw.append("\n<tr><td colspan='2' class='kd010'>"+ addr.getRegionalLangName() +"</td></tr>");
			else if(addr.getFirstName() != null && !"".equals(addr.getFirstName().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getFirstName() +(addr.getLastName()!=null&&!"".equals(addr.getLastName())?", "+addr.getLastName():"") +"</td></tr>");
			
			if(addr.getCoName() != null && !"".equals(addr.getCoName().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getNamePrefix() +"&nbsp;<span class='kd010'>"+ addr.getCoName() +"</span></td></tr>");
			
			if(addr.getStreetHindi1() != null && !"".equals(addr.getStreetHindi1().trim()))
				fw.append("\n<tr><td class='kd010' colspan='2'>"+ addr.getStreetHindi1() +"</td></tr>");
			else if(addr.getStreet1() != null && !"".equals(addr.getStreet1().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getStreet1() +"</td></tr>");

			if(addr.getStreetHindi2() != null && !"".equals(addr.getStreetHindi2().trim()))
				fw.append("\n<tr><td class='kd010' colspan='2'>"+ addr.getStreetHindi2() +"</td></tr>");
			else if(addr.getStreet2() != null && !"".equals(addr.getStreet2() .trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getStreet2() +"</td></tr>");

			if(addr.getCity() != null && !"".equals(addr.getCity().trim())){
				fw.append("\n<tr><td class='kd010' colspan='2'>"+ getCity(addr.getCountry(),addr.getStateOrRegion(), addr.getCity(),true) +"&nbsp;"+ getState(addr.getStateOrRegion(),addr.getCountry(),true)+"&nbsp;-&nbsp;"+ (addr.getZip()!=null?addr.getZip():"") +"</td></tr>");
			}else if(addr.getStateOrRegion() != null && !"".equals(addr.getStateOrRegion().trim())){
				fw.append("\n<tr><td class='kd010' colspan='2'>"+ getState(addr.getStateOrRegion(),addr.getCountry(),true) +"&nbsp;-&nbsp;"+ (addr.getZip()!=null?addr.getZip():"") +"</td></tr>");
			}
			if(addr.getCountry() != null && !"".equals(addr.getCountry().trim())){
				fw.append("\n<tr><td colspan='2'>"+ getCountry(addr.getCountry().trim(),false) +"</td></tr>");
			}
		}else{
			if(addr.getFirstName() != null && !"".equals(addr.getFirstName().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getFirstName() +(addr.getLastName()!=null&&!"".equals(addr.getLastName())?", "+addr.getLastName():"") +"</td></tr>");
			else if(addr.getRegionalLangName() != null && !"".equals(addr.getRegionalLangName().trim()))
				fw.append("\n<tr><td colspan='2' class='kd010'>"+ addr.getRegionalLangName() +"</td></tr>");
			
			if(addr.getStreet1() != null && !"".equals(addr.getStreet1().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getStreet1() +"</td></tr>");
			if(addr.getStreet2() != null && !"".equals(addr.getStreet2().trim()))
				fw.append("\n<tr><td colspan='2'>"+ addr.getStreet2() +"</td></tr>");

			if(addr.getCity() != null && !"".equals(addr.getCity().trim())){
				fw.append("\n<tr><td colspan='2'>"+ getCity(addr.getCountry(),addr.getStateOrRegion(), addr.getCity(),false) +"&nbsp;"+ getState(addr.getStateOrRegion(),addr.getCountry(),false) +"&nbsp;-&nbsp;"+ (addr.getZip()!=null?addr.getZip():"") +"</td></tr>");
			}else if(addr.getStateOrRegion() != null && !"".equals(addr.getStateOrRegion().trim())){
				fw.append("\n<tr><td colspan='2'>"+ getState(addr.getStateOrRegion(),addr.getCountry(),false) +"&nbsp;-&nbsp;"+ (addr.getZip()!=null?addr.getZip():"") +"</td></tr>");
			}
			if(addr.getCountry() != null && !"".equals(addr.getCountry().trim())){
				fw.append("\n<tr><td colspan='2'>"+ getCountry(addr.getCountry(),false) +"</td></tr>");
			}
		}
		if(addr.getInstruction() != null)
			fw.append("\n<tr><td colspan='2' class='info'>"+ addr.getInstruction() +"</td></tr>");

		fw.append("\n</table></td>");
		
		l++;
		
		if(qty <= 50) 
			return l;
		else
			return print(addr, qty-50, fw, l);
	}
	
	private boolean uploadResult(){
		try{
			String fileName = Config.getProperty("FILE_PATH") + instance.getReportInstanceId() + EXTN;
			File file = new File(fileName);
			BufferedReader fw = new BufferedReader(new FileReader(file));
			StringBuilder sb = new StringBuilder();
			
			String line = fw.readLine();
			while(line != null){
				sb.append(line);
				line = fw.readLine();
			}
			ByteArrayInputStream br = new ByteArrayInputStream(sb.toString().getBytes());
			int cnt = VyPrintLabelReportInstanceDAO.updateData(instance.getReportInstanceId(), br);
			if(cnt > 0){
				instance.setStatus(ReportStatusEnum.SUCCESS.getId());
			}else{
				instance.setStatus(ReportStatusEnum.FAILED.getId());
			}
			
			file.delete();
			
			return (cnt > 0);
		}catch(Exception e){
			return false;
		}
	}
	
	private String getCity(String country, String state, String city, boolean flg){
		if(cities.containsKey(country+"->"+state)){
			Map<String, ViewVyLookupCitiesDO> map = cities.get(country+"->"+state);
			ViewVyLookupCitiesDO dto = map.get(city);
			if(dto == null) return "";
			if(dto.getCityHindiName() != null && flg)
				return dto.getCityHindiName();
			else
				return dto.getCityName();
		}else
			return "";
	}

	private String getState(String state, String country, boolean flg){
		if(states.containsKey(country)){
			Map<String, ViewVyLookupCitiesDO> map = states.get(country);
			ViewVyLookupCitiesDO dto = map.get(state);
			if(dto == null) return "";
			if(dto.getStateHindiName() != null && flg)
				return dto.getStateHindiName();
			else
				return dto.getStateName();
		}else
			return "";
	}

	private String getCountry(String country, boolean flg){
		if(countries.containsKey(country)){
			ViewVyLookupCitiesDO dto = countries.get(country);
			if(dto == null) return "";
			if(dto.getCountryHindiName() != null && flg)
				return dto.getCountryHindiName();
			else
				return dto.getCountryName();
		}else
			return "";
	}

}
